<html><head><title>com.toedter.calendar.JTextFieldDateEditor</title></head><body><div id='tit'>com.toedter.calendar.JTextFieldDateEditor</div><div id='cate'>源码品读</div><div id='date'>2009年09月29日 星期二 12:04 P.M.</div><div id='page'>29</div><a id='url' href='http://hi.baidu.com/hxzon/blog/item/59efd0880d80a89ea5c27210.html'>http://hi.baidu.com/hxzon/blog/item/59efd0880d80a89ea5c27210.html</a><div id='cnt'><p>com.toedter.calendar.JTextFieldDateEditor</p> 
<p>构造函数中的maskPattern参数多余，可由datePattern推出，而两者不匹配会有错误效果。</p> 
<pre>/*
 *  Copyright (C) 2006 Kai Toedter
 *  kai@toedter.com
 *  www.toedter.com
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

package com.toedter.calendar;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.MaskFormatter;

/**
 * JTextFieldDateEditor is the default editor used by JDateChooser. It is a
 * formatted text field, that colores valid dates green/black and invalid dates
 * red. The date format patten and mask can be set manually. If not set, the
 * MEDIUM pattern of a SimpleDateFormat with regards to the actual locale is
 * used.
 * 
 * @author Kai Toedter
 * @version $LastChangedRevision: 97 $
 * @version $LastChangedDate: 2006-05-24 17:30:41 +0200 (Mi, 24 Mai 2006) $
 */
public class JTextFieldDateEditor extends JFormattedTextField implements IDateEditor, CaretListener, FocusListener,
        ActionListener {

    private static final long serialVersionUID = -8901842591101625304L;

    protected Date date;

    protected SimpleDateFormat dateFormatter;

    protected MaskFormatter maskFormatter;

    protected String datePattern;

    protected String maskPattern;

    protected char placeholder;

    protected Color darkGreen;

    protected DateUtil dateUtil;

    private boolean isMaskVisible;

    private boolean ignoreDatePatternChange;

    private int hours;

    private int minutes;

    private int seconds;

    private int millis;

    private Calendar calendar;

    public JTextFieldDateEditor() {
        this(false, null, null, ' ');
    }

    public JTextFieldDateEditor(String datePattern, String maskPattern, char placeholder) {
        this(true, datePattern, maskPattern, placeholder);
    }

    public JTextFieldDateEditor(boolean showMask, String datePattern, String maskPattern, char placeholder) {
        dateFormatter = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.MEDIUM);
        dateFormatter.setLenient(false);

        setDateFormatString(datePattern);
        if (datePattern != null) {
            ignoreDatePatternChange = true;
        }

        this.placeholder = placeholder;

        if (maskPattern == null) {
            this.maskPattern = createMaskFromDatePattern(this.datePattern);
        } else {
            this.maskPattern = maskPattern;
        }

        setToolTipText(this.datePattern);
        setMaskVisible(showMask);

        addCaretListener(this);
        addFocusListener(this);
        addActionListener(this);
        darkGreen = new Color(0, 150, 0);

        calendar = Calendar.getInstance();

        dateUtil = new DateUtil();
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.toedter.calendar.IDateEditor#getDate()
     */
    public Date getDate() {
        try {
            calendar.setTime(dateFormatter.parse(getText()));
            calendar.set(Calendar.HOUR_OF_DAY, hours);
            calendar.set(Calendar.MINUTE, minutes);
            calendar.set(Calendar.SECOND, seconds);
            calendar.set(Calendar.MILLISECOND, millis);
            date = calendar.getTime();
        } catch (ParseException e) {
            date = null;
        }
        return date;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.toedter.calendar.IDateEditor#setDate(java.util.Date)
     */
    public void setDate(Date date) {
        setDate(date, true);
    }

    /**
     * Sets the date.
     * 
     * @param date
     *            the date
     * @param firePropertyChange
     *            true, if the date property should be fired.
     */
    protected void setDate(Date date, boolean firePropertyChange) {
        Date oldDate = this.date;
        this.date = date;

        if (date == null) {
            setText(&quot;&quot;);
        } else {
            calendar.setTime(date);
            hours = calendar.get(Calendar.HOUR_OF_DAY);
            minutes = calendar.get(Calendar.MINUTE);
            seconds = calendar.get(Calendar.SECOND);
            millis = calendar.get(Calendar.MILLISECOND);

            String formattedDate = dateFormatter.format(date);
            try {
                setText(formattedDate);
            } catch (RuntimeException e) {
                e.printStackTrace();
            }
        }
        if (date != null &amp;&amp; dateUtil.checkDate(date)) {
            setForeground(Color.BLACK);

        }

        if (firePropertyChange) {
            firePropertyChange(&quot;date&quot;, oldDate, date);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.toedter.calendar.IDateEditor#setDateFormatString(java.lang.String)
     */
    public void setDateFormatString(String dateFormatString) {
        if (ignoreDatePatternChange) {
            return;
        }

        try {
            dateFormatter.applyPattern(dateFormatString);
        } catch (RuntimeException e) {
            dateFormatter = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.MEDIUM);
            dateFormatter.setLenient(false);
        }
        this.datePattern = dateFormatter.toPattern();
        setToolTipText(this.datePattern);
        setDate(date, false);
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.toedter.calendar.IDateEditor#getDateFormatString()
     */
    public String getDateFormatString() {
        return datePattern;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.toedter.calendar.IDateEditor#getUiComponent()
     */
    public JComponent getUiComponent() {
        return this;
    }

    /**
     * After any user input, the value of the textfield is proofed. Depending on
     * being a valid date, the value is colored green or red.
     * 
     * @param event
     *            the caret event
     */
    public void caretUpdate(CaretEvent event) {
        String text = getText().trim();
        String emptyMask = maskPattern.replace('#', placeholder);

        if (text.length() == 0 || text.equals(emptyMask)) {
            setForeground(Color.BLACK);
            return;
        }

        try {
            Date date = dateFormatter.parse(getText());
            if (dateUtil.checkDate(date)) {
                setForeground(darkGreen);
            } else {
                setForeground(Color.RED);
            }
        } catch (Exception e) {
            setForeground(Color.RED);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.awt.event.FocusListener#focusLost(java.awt.event.FocusEvent)
     */
    public void focusLost(FocusEvent focusEvent) {
        checkText();
    }

    private void checkText() {
        try {
            Date date = dateFormatter.parse(getText());
            setDate(date, true);
        } catch (Exception e) {
            // ignore
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.awt.event.FocusListener#focusGained(java.awt.event.FocusEvent)
     */
    public void focusGained(FocusEvent e) {
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.awt.Component#setLocale(java.util.Locale)
     */
    public void setLocale(Locale locale) {
        if (locale == getLocale() || ignoreDatePatternChange) {
            return;
        }

        super.setLocale(locale);
        dateFormatter = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
        setToolTipText(dateFormatter.toPattern());

        setDate(date, false);
        doLayout();
    }

    /**
     * Creates a mask from a date pattern. This is a very simple (and
     * incomplete) implementation thet works only with numbers. A date pattern
     * of &quot;MM/dd/yy&quot; will result in the mask &quot;##/##/##&quot;. Probably you want to
     * override this method if it does not fit your needs.
     * 
     * @param datePattern
     *            the date pattern
     * @return the mask
     */
    public String createMaskFromDatePattern(String datePattern) {
        String symbols = &quot;GyMdkHmsSEDFwWahKzZ&quot;;
        String mask = &quot;&quot;;
        for (int i = 0; i &lt; datePattern.length(); i++) {
            char ch = datePattern.charAt(i);
            boolean symbolFound = false;
            for (int n = 0; n &lt; symbols.length(); n++) {
                if (symbols.charAt(n) == ch) {
                    mask += &quot;#&quot;;
                    symbolFound = true;
                    break;
                }
            }
            if (!symbolFound) {
                mask += ch;
            }
        }
        return mask;
    }

    /**
     * Returns true, if the mask is visible.
     * 
     * @return true, if the mask is visible
     */
    public boolean isMaskVisible() {
        return isMaskVisible;
    }

    /**
     * Sets the mask visible.
     * 
     * @param isMaskVisible
     *            true, if the mask should be visible
     */
    public void setMaskVisible(boolean isMaskVisible) {
        this.isMaskVisible = isMaskVisible;
        if (isMaskVisible) {
            if (maskFormatter == null) {
                try {
                    maskFormatter = new MaskFormatter(createMaskFromDatePattern(datePattern));
                    maskFormatter.setPlaceholderCharacter(this.placeholder);
                    maskFormatter.install(this);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * Returns the preferred size. If a date pattern is set, it is the size the
     * date pattern would take.
     */
    public Dimension getPreferredSize() {
        if (datePattern != null) {
            return new JTextField(datePattern).getPreferredSize();
        }
        return super.getPreferredSize();
    }

    /**
     * Validates the typed date and sets it (only if it is valid).
     */
    public void actionPerformed(ActionEvent e) {
        checkText();
    }

    /**
     * Enables and disabled the compoment. It also fixes the background bug
     * 4991597 and sets the background explicitely to a
     * TextField.inactiveBackground.
     */
    public void setEnabled(boolean b) {
        super.setEnabled(b);
        if (!b) {
            super.setBackground(UIManager.getColor(&quot;TextField.inactiveBackground&quot;));
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.toedter.calendar.IDateEditor#getMaxSelectableDate()
     */
    public Date getMaxSelectableDate() {
        return dateUtil.getMaxSelectableDate();
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.toedter.calendar.IDateEditor#getMinSelectableDate()
     */
    public Date getMinSelectableDate() {
        return dateUtil.getMinSelectableDate();
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.toedter.calendar.IDateEditor#setMaxSelectableDate(java.util.Date)
     */
    public void setMaxSelectableDate(Date max) {
        dateUtil.setMaxSelectableDate(max);
        checkText();
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.toedter.calendar.IDateEditor#setMinSelectableDate(java.util.Date)
     */
    public void setMinSelectableDate(Date min) {
        dateUtil.setMinSelectableDate(min);
        checkText();
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.toedter.calendar.IDateEditor#setSelectableDateRange(java.util.Date,
     * java.util.Date)
     */
    public void setSelectableDateRange(Date min, Date max) {
        dateUtil.setSelectableDateRange(min, max);
        checkText();
    }

    /**
     * Creates a JFrame with a JCalendar inside and can be used for testing.
     * 
     * @param s
     *            The command line arguments
     */
    public static void main(String[] s) {
        JFrame frame = new JFrame(&quot;JTextFieldDateEditor&quot;);
        JTextFieldDateEditor jTextFieldDateEditor = new JTextFieldDateEditor();
        jTextFieldDateEditor.setDate(new Date());
        frame.getContentPane().add(jTextFieldDateEditor);
        frame.pack();
        frame.setVisible(true);
    }
}</pre> 
<p><br /> </p></div></body></html>